use serde::{Serialize, Deserialize};
use serde_json::json;
use sha2::{Sha256, Digest};
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Block {
    index: u64,
    previous_hash: String,
    timestamp: u64,
    data: String,
    nonce: u64,
    hash: String,
}

impl Block {
    fn new(index: u64, previous_hash: String, timestamp: u64, data: String, nonce: u64) -> Self {
        let mut block = Block {
            index,
            previous_hash,
            timestamp,
            data,
            nonce,
            hash: String::new(),
        };
        block.hash = block.calculate_hash();
        block
    }

    fn calculate_hash(&self) -> String {
        let block_data = json!({
            "index": self.index,
            "previous_hash": self.previous_hash,
            "timestamp": self.timestamp,
            "data": self.data,
            "nonce": self.nonce
        });
        
        let block_string = block_data.to_string();
        let mut hasher = Sha256::new();
        hasher.update(block_string);
        format!("{:x}", hasher.finalize())
    }
}

struct Miner {
    name: String,
    hash_power: u64, // 每秒能尝试的哈希次数
}

impl Miner {
    fn new(name: &str, hash_power: u64) -> Self {
        Miner {
            name: name.to_string(),
            hash_power,
        }
    }

    fn mine(&self, block: &Block, difficulty: u8) -> Block {
        // 复制区块进行挖矿
        let mut mining_block = block.clone();
        
        // 目标前缀
        let target_prefix = "0".repeat(difficulty as usize);
        
        // 记录开始时间
        let start_time = SystemTime::now();
        let mut attempts = 0;
        
        // 挖矿循环
        while !mining_block.hash.starts_with(&target_prefix) {
            mining_block.nonce += 1;
            mining_block.hash = mining_block.calculate_hash();
            attempts += 1;
            
            // 简单模拟不同哈希能力的矿工
            if attempts % 1000 == 0 {
                let elapsed = start_time.elapsed().unwrap().as_secs_f64();
                if (attempts as f64) > elapsed * (self.hash_power as f64) {
                    // 这里可以添加适当的暂停逻辑来模拟不同挖矿速度
                    // 为了简单起见，我们在Rust实现中省略实际的暂停
                }
            }
        }
        
        // 计算挖矿时间
        let mining_time = start_time.elapsed().unwrap().as_secs_f64();
        
        println!("{} 挖到了区块! 尝试次数: {}, 用时: {:.4}秒, 哈希值: {}",
                 self.name, attempts, mining_time, mining_block.hash);
        
        mining_block
    }
}

fn get_current_timestamp() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("Time went backwards")
        .as_secs()
}

fn main() {
    // 创建创世区块
    let genesis_block = Block::new(
        0,
        "0".to_string(),
        get_current_timestamp(),
        "Genesis Block".to_string(),
        0,
    );
    
    // 创建新区块
    let mut new_block = Block::new(
        1,
        genesis_block.hash.clone(),
        get_current_timestamp(),
        "Transaction Data".to_string(),
        0,
    );
    
    // 创建不同哈希能力的矿工
    let miners = vec![
        Miner::new("矿工1（弱）", 1000),
        Miner::new("矿工2（中）", 5000),
        Miner::new("矿工3（强）", 10000),
    ];
    
    // 设置挖矿难度
    let difficulty = 4; // 4个0开头
    
    println!("开始挖矿竞赛! 难度: {}", difficulty);
    println!("目标前缀: {}", "0".repeat(difficulty as usize));
    
    // 记录挖矿结果
    let mut results = Vec::new();
    
    // 模拟挖矿过程
    for miner in &miners {
        // 重置nonce，确保公平竞争
        new_block.nonce = 0;
        new_block.hash = new_block.calculate_hash();
        
        // 每个矿工独立挖矿
        let start_time = SystemTime::now();
        let mined_block = miner.mine(&new_block, difficulty);
        let end_time = SystemTime::now();
        let mining_duration = end_time.duration_since(start_time).unwrap().as_secs_f64();
        
        results.push((miner.name.clone(), mining_duration, mined_block));
    }
    
    // 按挖矿时间排序
    results.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
    
    // 显示竞赛结果
    println!("\n挖矿竞赛结果:");
    for (i, (miner_name, time, _)) in results.iter().enumerate() {
        println!("第{}名: {}, 用时: {:.4}秒", i + 1, miner_name, time);
    }
    
    // 显示获胜区块信息
    let (winning_miner, _winning_time, winning_block) = &results[0];
    println!("\n获胜区块信息:");
    println!("获胜矿工: {}", winning_miner);
    println!("索引: {}", winning_block.index);
    println!("Nonce: {}", winning_block.nonce);
    println!("哈希值: {}", winning_block.hash);
    
    // 验证区块
    let is_valid = winning_block.hash.starts_with(&"0".repeat(difficulty as usize));
    println!("区块验证: {}", if is_valid { "有效" } else { "无效" });
}